package com.luhuiguo.sso.service.impl;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataAccessException;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.transaction.annotation.Transactional;

import com.luhuiguo.sso.Constants;
import com.luhuiguo.sso.dao.UserDao;
import com.luhuiguo.sso.entity.Persona;
import com.luhuiguo.sso.entity.User;
import com.luhuiguo.sso.exception.UserExistsException;
import com.luhuiguo.sso.service.RoleManager;
import com.luhuiguo.sso.service.UserManager;
import com.luhuiguo.sso.web.model.RegistrationInfo;

@Transactional
public class UserManagerImpl implements UserManager {

	private UserDao userDao;

	private RoleManager roleManager;

	private PasswordEncoder passwordEncoder;

	@Required
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	@Required
	public void setRoleManager(RoleManager roleManager) {
		this.roleManager = roleManager;
	}

	@Required
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	@Override
	@Transactional(readOnly = true)
	public User getUser(Long id) {
		return userDao.get(id);
	}

	@Override
	@Transactional(readOnly = true)
	public User getUser(String username) {
		List<User> users = userDao.findByProperty("username", username); //$NON-NLS-1$
		if (users.size() == 0) {
			return null;
		}
		return users.get(0);
	}

	@Override
	@Transactional(readOnly = true)
	public List<User> getAllUser(int... rowStartIdxAndCount) {
		return userDao.findAll(rowStartIdxAndCount);
	}

	@Override
	public User createUser(String username, String rawPass, String email) {

		if (existsUser(username)) {
			throw new UserExistsException("Username already exists:" + username);
		}
		User user = new User(username, passwordEncoder.encodePassword(rawPass,
				null), email);
		user.getRoles().add(roleManager.getUserRole());

		createUser(user);

		return user;
	}

	@Override
	public User createUser(RegistrationInfo reg) {
		if (existsUser(reg.getUsername())) {
			throw new UserExistsException("Username already exists:"
					+ reg.getUsername());
		}
		User user = new User(reg.getUsername(), passwordEncoder.encodePassword(
				reg.getPassword(), null), reg.getEmail());

		Persona persona = new Persona();
		persona.setUser(user);
		persona.setName(Constants.DEFAULT_PERSONA);
		persona.setNickname(reg.getNickname());
		persona.setEmail(reg.getEmail());
		persona.setFullname(reg.getFullname());
		persona.setBod(reg.getBod());
		persona.setGender(reg.getGender());
		persona.setPostcode(reg.getPostcode());
		persona.setCountry(reg.getCountry());
		persona.setLanguage(reg.getLanguage());
		persona.setTimezone(reg.getTimezone());

		user.getPersonas().add(persona);

		user.setDefaultPersona(persona);

		user.getRoles().add(roleManager.getUserRole());

		createUser(user);
		return user;
	}

	@Override
	public void createUser(User user, boolean raw) {
		if (raw) {
			user.setPassword(passwordEncoder.encodePassword(user.getPassword(),
					null));
		}
		userDao.create(user);
	}

	@Override
	public void createUser(User user) {
		createUser(user, false);
	}

	@Override
	public void deleteUser(Long id) {
		userDao.delete(id);

	}

	@Override
	public void deleteUser(String username) {
		deleteUser(getUser(username));

	}

	@Override
	public void deleteUser(User user) {
		userDao.delete(user);

	}

	@Override
	public void updateUser(User user) {
		userDao.update(user);

	}

	@Override
	@Transactional(readOnly = true)
	public boolean existsUser(Long id) {
		return userDao.exists(id);
	}

	@Override
	@Transactional(readOnly = true)
	public boolean existsUser(String username) {
		return getUser(username) != null;
	}

	@Override
	@Transactional(readOnly = true)
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {
		List<User> users = userDao.findByProperty("username", username);
		if (users.size() == 0) {
			throw new UsernameNotFoundException("Uername not found:" + username);

		}
		User user = users.get(0);

		return user;
	}

	@Override
	public void updatePassword(User user, String rawPass) {
		user.setPassword(passwordEncoder.encodePassword(rawPass, null));
		updateUser(user);
	}

	@Override
	public void updatePassword(String username, String rawPass) {
		updatePassword(getUser(username), rawPass);

	}

	@Override
	@Transactional(readOnly = true)
	public boolean validatePassword(User user, String rawPass) {
		if (null == user) {
			return false;
		}
		return StringUtils.equals(rawPass, user.getPassword());
	}

	@Override
	@Transactional(readOnly = true)
	public boolean validatePassword(String username, String rawPass) {
		return validatePassword(getUser(username), rawPass);
	}

}
